"""
Case Type   : 故障&可靠性测试
Case Name   : 主机异常，恢复后备机扩容成功
Create At   : 2022/4/8
Owner       : n@ningyali
Description :
    1、构造主机异常场景，比如主库shutdown
    2、备机扩容
    3、恢复主机故障
    4、备机扩容
    5、查询数据库集群状态
    6、查看主备数据
Expect      :
    1、故障注入成功
    2、备机扩容失败
    3、故障恢复成功
    4、备机扩容成功
    5、数据库集群状态正常
    6、数据一致
History     :
"""
import os
import re
import unittest

from yat.test import macro

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH, RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger


class GsExpansion20(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.sh = {'pri_root': CommonSH('PrimaryRoot'),
                   'pri_user': CommonSH(self.nodes_tuple[0]),
                   'sta1_user': CommonSH(self.nodes_tuple[1]),
                   'sta2_user': CommonSH(self.nodes_tuple[2])}
        self.node_num = self.sh['pri_user'].get_node_num()
        self.log = Logger()
        self.cons = Constant()
        self.com = Common()
        self.t_name = 't_expansion_20'
        text = f'-----{os.path.basename(__file__)} start-----'
        self.log.info(text)

        text = '----预置步骤: 一主两备减容一备，后续用例才能扩容 expect: 成功----'
        self.log.info(text)
        expect_msg = 'Success to drop the target nodes'
        shell_cmd = f'''source {macro.DB_ENV_PATH};
                    expect <<EOF
                    set timeout 300
                    spawn gs_dropnode -U {self.sh['pri_user'].node.ssh_user} \
                    -G {self.sh['pri_user'].node.ssh_user} \
                    -h {self.sh.get("sta1_user").node.ssh_host}
                    expect "*(yes/no)?"
                    send "yes\\n"
                    expect eof''' + "\nEOF\n"
        self.log.info(shell_cmd)
        res = self.com.get_sh_result(self.sh['pri_user'].node, shell_cmd)
        self.assertIn(expect_msg, res, f'执行失败: {text}')

        text = '---预置步骤: 数据库主机解压安装包，以免找不到扩容脚本 expect: 成功---'
        self.log.info(text)
        cmd = f'cd {os.path.dirname(macro.DB_SCRIPT_PATH)} && ' \
            f'tar -xf openGauss-Package-bak*.tar.gz && ' \
            f'ls {macro.DB_SCRIPT_PATH}|grep gs_sshexkey'
        self.log.info(cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node, cmd)
        self.assertEqual(res, 'gs_sshexkey', f'执行失败: {text}')

        text = '----预置步骤: 创建测试表，插入测试数据 expect: 成功----'
        self.log.info(text)
        sql_cmd = f'drop table if exists {self.t_name};' \
            f'create table {self.t_name}(col1 int, col2 text);' \
            f'insert into {self.t_name} values ' \
            f'(generate_series(1,10000), generate_series(1,10000)||\'test\');'
        res = self.sh['pri_user'].executDbSql(sql_cmd)
        self.log.info(res)
        self.assertIn(self.cons.CREATE_TABLE_SUCCESS, res, f'执行失败: {text}')
        self.assertIn('INSERT 0 10000', res, f'执行失败: {text}')

        text = '----预置步骤: 建立root互信 expect: 成功----'
        self.log.info(text)
        ssh_cmd = f'cd {macro.DB_SCRIPT_PATH};' \
            f'echo "{self.sh.get("pri_root").node.ssh_host}\n' \
            f'{self.sh.get("sta1_user").node.ssh_host}\n' \
            f'{self.sh.get("sta2_user").node.ssh_host}" > hosts\n'
        ssh_cmd += f'''expect <<EOF
                            set timeout 300
                            spawn ./gs_sshexkey -f hosts
                            expect "*assword:"
                            send "{self.sh.get(
            "pri_root").node.ssh_password}\\n"
                            expect eof''' + "\nEOF\n"
        ssh_cmd += "source ~/.bashrc"
        self.log.info(ssh_cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node, ssh_cmd)
        self.assertIn('Successfully created SSH trust', res, f'执行失败: {text}')

    def test_1(self):
        text = '----step1: 构造主机异常场景，比如主库shutdown expect: 故障注入成功----'
        self.log.info(text)
        sql_cmd = 'shutdown;'
        res = self.sh['pri_user'].executDbSql(sql_cmd)
        self.log.info(res)
        self.assertIn('SHUTDOWN', res, f'执行失败: {text}')

        text = '----step2: 备机扩容 expect: 备机扩容失败----'
        self.log.info(text)
        expansion_cmd = f'cd {macro.DB_SCRIPT_PATH};' \
            f'source {macro.DB_ENV_PATH}\n' \
            f'./gs_expansion -U {self.sh.get("pri_user").node.ssh_user} ' \
            f'-G {self.sh.get("pri_user").node.ssh_user} ' \
            f'-X {macro.DB_XML_PATH} ' \
            f'-h {self.sh.get("sta1_user").node.ssh_host} -L'
        self.log.info(expansion_cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node,
                                     expansion_cmd)
        self.assertIn('The status of primary is not Normal', res,
                      f'执行失败: {text}')

        text = '----step3: 恢复主机故障 expect: 故障恢复成功----'
        self.log.info(text)
        start_res = self.sh['pri_user'].startDbInstance()
        self.log.info(start_res)
        self.assertIn(self.cons.RESTART_SUCCESS_MSG, start_res, f'执行失败: {text}')

        text = '----step4: 备机扩容 expect: 备机扩容成功----'
        self.log.info(text)
        expansion_cmd = f'cd {macro.DB_SCRIPT_PATH};' \
            f'source {macro.DB_ENV_PATH}\n' \
            f'./gs_expansion -U {self.sh.get("pri_user").node.ssh_user} ' \
            f'-G {self.sh.get("pri_user").node.ssh_user} ' \
            f'-X {macro.DB_XML_PATH} ' \
            f'-h {self.sh.get("sta1_user").node.ssh_host} -L'
        self.log.info(expansion_cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node,
                                     expansion_cmd)
        expect = 'Expansion results:.*:.*Success.*Expansion Finish.'
        regex_res = re.search(expect, res, re.S)
        self.assertIsNotNone(regex_res, f'执行失败: {text}')

        text = '----step5: 查询数据库集群状态 expect: 数据库集群状态正常----'
        self.log.info(text)
        res = self.sh['pri_user'].getDbClusterStatus('detail')
        self.log.info(res)
        self.assertEqual(res.count('Normal'), self.node_num + 1,
                         f'执行失败: {text}')

        text = '----step6: 查看主备数据 expect: 数据一致----'
        self.log.info(text)
        nodes = (self.sh['pri_user'].node,
                 self.sh['sta1_user'].node,
                 self.sh['sta2_user'].node)
        flag = self.com.check_data_sample_by_all(r'\d', *nodes)
        self.assertTrue(flag)

        table_dict = self.com.format_sql_result(
            self.sh['pri_user'].executDbSql(r'\d'))
        table_name = table_dict.get('Name')
        for name in table_name:
            select_sql = f'select count(*) from {name};'
            flag = self.com.check_data_sample_by_all(select_sql,
                                                     *nodes)
            self.assertTrue(flag)

    def tearDown(self):
        text = '----run teardown----'
        self.log.info(text)

        text1 = f'----删除表----'
        self.log.info(text1)
        sql_cmd = f'drop table if exists {self.t_name};'
        res1 = self.sh['pri_user'].executDbSql(sql_cmd)
        self.log.info(res1)

        text2 = f'----检查集群状态是否正常----'
        self.log.info(text2)
        res2 = self.sh['pri_user'].getDbClusterStatus('detail')
        self.log.info(res2)

        self.assertIn(self.cons.DROP_TABLE_SUCCESS, res1, f'执行失败: {text1}')
        self.assertEqual(res2.count('Normal'), self.node_num + 1,
                         f'执行失败: {text2}')

        text = f'-----{os.path.basename(__file__)} end-----'
        self.log.info(text)
